# textbook_rsa_cca_attack.py

import secrets
from publickey.math_utils import generate_prime_number, extended_gcd, mod_inverse, power

class TextbookRSA:
    """
    一个不使用任何填充的“教科书式”RSA实现，用于演示漏洞。
    警告：绝对不能在实际应用中使用此类实现！
    """
    def __init__(self, bits=1024):
        p = generate_prime_number(bits // 2)
        q = generate_prime_number(bits // 2)
        while p == q:
            q = generate_prime_number(bits // 2)
        
        self.n = p * q
        phi_n = (p - 1) * (q - 1)
        self.e = 65537
        while extended_gcd(self.e, phi_n)[0] != 1:
            self.e = 2 * secrets.randbelow((phi_n - 3) // 2) + 3 # 备用e
        
        self.d = mod_inverse(self.e, phi_n)

    def encrypt(self, message_int: int) -> int:
        """加密一个整数"""
        if not (0 <= message_int < self.n):
            raise ValueError("消息必须在 [0, n-1) 范围内")
        return power(message_int, self.e, self.n)

    def decrypt(self, ciphertext_int: int) -> int:
        """解密一个整数"""
        return power(ciphertext_int, self.d, self.n)

def demonstrate_textbook_rsa_cca():
    """
    主函数：完整演示对教科书式RSA的选择密文攻击。
    """
    print("="*20, "演示对教科书式RSA的CCA攻击", "="*20)

    # --- 场景设置 ---
    # 1. 受害者(Victim)创建一个教科书式RSA密钥对
    victim_rsa = TextbookRSA(bits=1024)
    print("受害者创建了一个不安全的、无填充的RSA密钥对。")
    
    # 2. 原始的秘密消息
    original_message = b"Your final exam grade is: A+"
    original_message_int = int.from_bytes(original_message, 'big')
    print(f"原始的秘密消息: '{original_message.decode()}' (整数形式: {original_message_int})")

    # 3. 受害者加密消息，准备发送
    # (在真实场景中，这一步由发送方完成，密文被攻击者截获)
    ciphertext_c = victim_rsa.encrypt(original_message_int)
    print(f"原始密文 C 被攻击者截获。")

    print("\n" + "-"*15, "攻击开始", "-"*15)

    # --- 攻击者 (Attacker) 的操作 ---
    # 4. 攻击者选择一个随机数 r
    r = secrets.randbelow(victim_rsa.n - 2) + 2 # 选择一个 [2, n-1] 范围的 r
    print(f"1. 攻击者选择一个随机数 r = {r}")

    # 5. 攻击者计算 r^e mod n
    r_pow_e = power(r, victim_rsa.e, victim_rsa.n)

    # 6. 攻击者构造新的、篡改过的密文 C'
    tampered_ciphertext_c_prime = (ciphertext_c * r_pow_e) % victim_rsa.n
    print(f"2. 攻击者构造了新的密文 C' = C * (r^e) mod n")

    # --- “解密预言机” (Decryption Oracle) 交互 ---
    # 7. 攻击者将 C' 发送给受害者请求解密
    print(f"3. 攻击者将 C' 发送给受害者的解密服务（预言机）。")
    decrypted_m_prime = victim_rsa.decrypt(tampered_ciphertext_c_prime)
    print(f"4. 受害者解密 C' 后，得到结果 M' = {decrypted_m_prime}")

    # --- 攻击者恢复原始明文 ---
    # 8. 攻击者计算 r 的模逆元
    r_inverse = mod_inverse(r, victim_rsa.n)
    
    # 9. 攻击者用 M' 和 r_inverse 恢复原始明文 M
    recovered_message_int = (decrypted_m_prime * r_inverse) % victim_rsa.n
    print(f"5. 攻击者计算 M = M' * r^-1 mod n 来恢复原始消息。")
    
    # --- 验证 ---
    recovered_message_bytes = recovered_message_int.to_bytes((recovered_message_int.bit_length() + 7) // 8, 'big')
    
    print("\n" + "="*20, "攻击结果", "="*20)
    print(f"攻击者恢复出的消息: '{recovered_message_bytes.decode()}'")
    
    if recovered_message_int == original_message_int:
        print("++ 攻击成功！攻击者在不知道私钥的情况下，完全恢复了原始的秘密消息。")
    else:
        print("-- 攻击失败，代码或逻辑有误。")


if __name__ == "__main__":
    demonstrate_textbook_rsa_cca()
    